<?php
require_once dirname(__DIR__) . "/wechat/lib/WxPay.Api.php";
require_once dirname(__DIR__) . "/wechat/lib/WxPay.Notify.php";
require_once dirname(__DIR__) . "/wechat/example/WxPay.JsApiPay.php";
require_once dirname(__DIR__) . '/wechat/example/log.php';
require_once dirname(__DIR__) . '/wechat/example/phpqrcode/phpqrcode.php';

require_once 'Tools.php';

/**
 * 统一支付类
 */
class Pay {
  private static $payBody = '红包发放-充值';
  private static $weChatNotifyUrl = 'https://www.ws1j.net/track/index.php/Track/wechatnotify';

  public static function redpacket($redPacketId, $openId) {
    $ret = array('data'=>null, 'info'=>'success', 'status'=>1);
    // 商户订单号
    $orderId = self::_genOrderId('');

    // 红包信息
    $rpData = M("RedpacketList")->find($redPacketId);
    $postId = $rpData['rp_postid'];

    // 帖子信息
    $postData = M("Post")->find($postId);

    try {
      $WxPayRedPacket = new WxPayRedPacket();
      $WxPayRedPacket->SetMch_billno($orderId); // 商户订单号
      $WxPayRedPacket->SetOpenid($openId); // 用户的openid
      $WxPayRedPacket->SetTotalAmount($rpData['rp_price'] * 100); // 红包金额，单位为分
      $WxPayRedPacket->SetTotalNum(1); // 发放人数，默认为1
      $WxPayRedPacket->SetWishing('大吉大利，恭喜发财'); // 祝福语
      $WxPayRedPacket->SetActName($postData['post_title']); // 活动名称，取帖子标题
      $WxPayRedPacket->SetRemark($postData['post_subtitle']); // 活动备注，取帖子副标题
      $result = WxPayApi::redpacket($WxPayRedPacket);
      $ret['data'] = $result;
      if($result["return_code"] != "SUCCESS") {
        $ret['info'] = $result['return_msg'];
        $ret['status'] = 0;
        return $ret;
      }
    }catch (Exception $e){
      $ret['info'] = $e->getMessage();
      $ret['status'] = 0;
      return $ret;
    }

    if($ret['status'] === 1) {
      $saveData['rp_id'] = $redPacketId;
      $saveData['rp_order'] = $orderId;
      M("RedpacketList")->save($saveData);
    }

    $ret['info'] = trace();
    return $ret;
  }

  /**
   * 下单
   * @param string $channel 支付方式，目前支持wechat
   * @param string $platform 支付平台，目前有wechat(公众号),desktop
   * @return array 支付结果 {data, info, status}
   */
  public static function order($channel, $platform, $postId, $userId, $openId = false){
    $ret = array('data'=>null, 'info'=>'success', 'status'=>1);

    $postData = M('Post')->find($postId);
    $price = $postData['post_redpacket_price'];

    // 生成订单Id
    $orderId = self::_genOrderId($channel);
    $ret['data']['id'] = $orderId;

    // 第三方支付下单
    try {
      if ($channel === 'wechat') {
        $order = self::_wechatOrder($ret['data'], $platform, $orderId, $postId, $openId, $price);
      }
    }catch (Exception $e){
      $ret['info'] = $e->getMessage();
      $ret['status'] = 0;
      return $ret;
    }

    // 下单成功，订单信息添加到后台
    if($ret['status'] === 1) {
      $Orders = M("Orders");
      $addData['order_id'] = $orderId;
      $addData['order_postid'] = $postId;
      $addData['order_userid'] = $userId;
      $addData['order_channel'] = $channel;
      $addData['order_platform'] = $platform;
      $addData['order_price'] = $price;
      $addData['order_status'] = 0;
      $addData['order_time'] = time();
      $addData['order_prepayid'] = $order['prepay_id'] ? $order['prepay_id'] : '';
      $res = $Orders->add($addData);
    }
    $ret['info'] = trace();

    return $ret;
  }

  /**
   * 微信下单
   * @param array $retData 返回数据的引用
   * @param string $platform 支付平台
   * @param string $orderId 订单id
   * @param string $openId openid
   * @param float $price 订单价格
   * @return array $order 订单信息
   */
  private static function _wechatOrder(&$retData, $platform, $orderId, $productId, $openId, $price) {
    $input = new WxPayUnifiedOrder();
    $input->SetBody(self::$payBody);
    $input->SetOut_trade_no($orderId);
    $input->SetTotal_fee($price * 100); // 微信下单的价格单位为分
    $input->SetNotify_url(self::$weChatNotifyUrl);
    if ($platform === 'desktop') {
      $input->SetTrade_type("NATIVE");
      $input->SetProduct_id($productId);
      $order = WxPayApi::unifiedOrder($input);
      $src = self::_getQRCodeSrc($order["code_url"]);
      $retData['src'] = $src;
    }else if ($platform === 'wechat') {
      $input->SetTrade_type("JSAPI");
      $input->SetOpenid($openId);
      $order = WxPayApi::unifiedOrder($input);
      $tools = new JsApiPay();
      $retData['data'] = json_decode($tools->GetJsApiParameters($order), true);
    }
    return $order;
  }

  /**
   * 生成二维码并返回base64编码的图片数据
   * @param string $url 二维码的信息
   * @return string base64图片信息
   */
  private static function _getQRCodeSrc($url) {
    ob_start();
    QRcode::png($url, false, QR_ECLEVEL_L, 5, 0);
    $src = base64_encode(ob_get_contents());
    ob_end_clean();
    return $src;
  }

  /**
   * 生成订单id = 支付方式 + 时间戳 + 6位盐
   * @param string $channel 支付方式
   * @return string 订单id
   */
  private static function _genOrderId($channel) {
    $salt = Tools::getSalt(6);
    $timestamp = time();
    return $channel.$timestamp.$salt;
  }

  /**
   * 微信异步通知
   * @return void
   */
  public static function wechatNotify() {
    $logPath = $_SERVER['DOCUMENT_ROOT']."/track/Runtime/WechatLogs/".date('Y-m-d').'.log';
    $logHandler= new CLogFileHandler($logPath);
    $log = WeChatLog::Init($logHandler, 15);
    WeChatLog::DEBUG("begin notify");
    $notify = new PayNotifyCallBack();
    $notify->Handle(false);
  }

  /**
   * 完成订单
   * @param string $orderId 订单id
   * @param float $postPrice 订单价格
   * @param string $tradeNo 第三方支付的订单号，微信支付无需传入此参数
   * @return void
   */
  public static function _finishOrder($orderId, $postPrice, $tradeNo = false) {
    // 验签成功，修改订单状态
    $Orders = M("Orders");
    $orderData = $Orders->find($orderId);

    $priceMatch = bccomp(floatval($orderData['order_price']), floatval($postPrice), 2) === 0;
    // 订单为未完成状态，且交易金额匹配时
    if($orderData['order_status'] != 1 && $priceMatch){
      $saveData['order_id'] = $orderId;
      $saveData['order_status'] = 1; // 表示已完成
      $saveData['order_finishtime'] = time();
      if($tradeNo) $saveData['order_prepayid'] = $tradeNo;
      $ret = $Orders->save($saveData);
      
      $postId = $orderData['order_postid'];
      $postData['post_id'] = $postId;
      $postData['post_status'] = 0;
      M('Post')->save($postData);
    }
  }

  public static function verifyOrder($outTradeNo) {
    $input = new WxPayOrderQuery();
    $input->SetOut_trade_no($outTradeNo);
    $result = WxPayApi::orderQuery($input);
    if(array_key_exists("return_code", $result)
      && array_key_exists("result_code", $result)
      && array_key_exists("trade_state", $result)
      && $result["return_code"] == "SUCCESS"
      && $result["result_code"] == "SUCCESS"
      && $result["trade_state"] == "SUCCESS")
    {
      return true;
    }
    return false;
  }
}

/**
 * 微信支付通知类
 */
class PayNotifyCallBack extends WxPayNotify
{
  //查询订单
  public function Queryorder($transaction_id)
  {
    $input = new WxPayOrderQuery();
    $input->SetTransaction_id($transaction_id);
    $result = WxPayApi::orderQuery($input);
    WeChatLog::DEBUG("query:" . json_encode($result));
    if(array_key_exists("return_code", $result)
      && array_key_exists("result_code", $result)
      && $result["return_code"] == "SUCCESS"
      && $result["result_code"] == "SUCCESS")
    {
      return true;
    }
    return false;
  }

  //重写回调处理函数
  public function NotifyProcess($data, &$msg)
  {
    WeChatLog::DEBUG("call back:" . json_encode($data));
    $notfiyOutput = array();

    if(!array_key_exists("transaction_id", $data)){
      $msg = "输入参数不正确";
      return false;
    }
    //查询订单，判断订单真实性
    if(!$this->Queryorder($data["transaction_id"])){
      $msg = "订单查询失败";
      return false;
    }
    if($data['mch_id'] !== WxPayConfig::MCHID) {
      $msg = '商户号不匹配';
      return false;
    }
    //查询成功，修改商户订单状态
    Pay::_finishOrder($data['out_trade_no'], $data['total_fee'] / 100);

    return true;
  }
}
